import { Request, Response } from 'express';
import catchAsync from '@/utils/catchAsync';
import { NotesService } from '@/services/notes';
import { AuthenticatedRequest } from '@/middleware/auth';
import path from 'path';
import { generateUniqueFilename } from '@/utils/upload';
import { hasS3, uploadBufferToS3 } from '@/utils/s3';
import SocketService from '@/services/socket';
import { prisma } from '@/config/database';

export const NotesController = {
  // Groups
  listGroups: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const userId = req.user!.id;
    const groups = await NotesService.listGroups(userId);
    res.json({ success: true, data: groups });
  }),
  createGroup: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const userId = req.user!.id;
    const { name } = req.body;
    const g = await NotesService.createGroup(userId, name);
    const me = await prisma.user.findUnique({ where: { id: userId }, select: { partnerId: true } });
    const notify = [userId, ...(me?.partnerId ? [me.partnerId] : [])].map(uid => `user_${uid}`);
    SocketService.instance?.getIO().to(notify).emit('notes_updated', { scope: 'groups', groupId: g.id });
    res.json({ success: true, data: g });
  }),
  renameGroup: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const userId = req.user!.id;
    const { id } = req.params;
    const { name } = req.body;
    const g = await NotesService.renameGroup(userId, id, name);
    const me = await prisma.user.findUnique({ where: { id: userId }, select: { partnerId: true } });
    const notify = [userId, ...(me?.partnerId ? [me.partnerId] : [])].map(uid => `user_${uid}`);
    SocketService.instance?.getIO().to(notify).emit('notes_updated', { scope: 'groups', groupId: id });
    res.json({ success: true, data: g });
  }),
  deleteGroup: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const userId = req.user!.id;
    const { id } = req.params;
    await NotesService.deleteGroup(userId, id);
    const me = await prisma.user.findUnique({ where: { id: userId }, select: { partnerId: true } });
    const notify = [userId, ...(me?.partnerId ? [me.partnerId] : [])].map(uid => `user_${uid}`);
    SocketService.instance?.getIO().to(notify).emit('notes_updated', { scope: 'groups', groupId: id, deleted: true });
    res.json({ success: true, message: '分组已删除' });
  }),

  // Notes
  listNotes: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const userId = req.user!.id;
    const groupId = (req.query.groupId as string) || undefined;
    const notes = await NotesService.listNotes(userId, groupId);
    res.json({ success: true, data: notes });
  }),
  createNote: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const userId = req.user!.id;
    const note = await NotesService.createNote(userId, req.body);
    const me = await prisma.user.findUnique({ where: { id: userId }, select: { partnerId: true } });
    const notify = [userId, ...(me?.partnerId ? [me.partnerId] : [])].map(uid => `user_${uid}`);
    SocketService.instance?.getIO().to(notify).emit('notes_updated', { scope: 'notes', groupId: note.groupId });
    res.json({ success: true, data: note });
  }),
  updateNote: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const userId = req.user!.id;
    const { id } = req.params;
    const note = await NotesService.updateNote(userId, id, req.body);
    const me = await prisma.user.findUnique({ where: { id: userId }, select: { partnerId: true } });
    const notify = [userId, ...(me?.partnerId ? [me.partnerId] : [])].map(uid => `user_${uid}`);
    SocketService.instance?.getIO().to(notify).emit('notes_updated', { scope: 'notes', groupId: note.groupId });
    res.json({ success: true, data: note });
  }),
  deleteNote: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const userId = req.user!.id;
    const { id } = req.params;
    // 查询便签以便拿到 groupId（简单起见再查一次）
    const existing = await (await import('@/config/database')).prisma.note.findUnique({ where: { id }, select: { groupId: true }});
    await NotesService.deleteNote(userId, id);
    const me = await prisma.user.findUnique({ where: { id: userId }, select: { partnerId: true } });
    const notify = [userId, ...(me?.partnerId ? [me.partnerId] : [])].map(uid => `user_${uid}`);
    SocketService.instance?.getIO().to(notify).emit('notes_updated', { scope: 'notes', groupId: existing?.groupId, deleted: true });
    res.json({ success: true, message: '便签已删除' });
  }),
  addTime: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const userId = req.user!.id;
    const { id } = req.params;
    const { seconds } = req.body;
    const result = await NotesService.addTime(userId, id, Number(seconds) || 0);
    res.json({ success: true, data: result });
  }),

  // Attachments：优先对象存储，未配置则回退本地
  uploadAttachment: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const { id } = req.params; // noteId
    const file = (req as any).file as Express.Multer.File;
    if (!file) {
      res.status(400).json({ success: false, message: '未收到文件' });
      return;
    }

    let url: string
    if (hasS3() && file.buffer) {
      const unique = generateUniqueFilename(file.originalname)
      const key = `notes/${id}/${unique}`
      url = await uploadBufferToS3(key, file.buffer, file.mimetype)
    } else if ((file as any).path) {
      // 本地回退：使用磁盘路径（仅在使用 diskStorage 时）
      url = `/uploads/${path.basename((file as any).path)}`
    } else {
      res.status(500).json({ success: false, message: '上传配置异常' })
      return
    }

    const att = await NotesService.addAttachment(id, {
      kind: (req.body.kind as string) || 'file',
      name: file.originalname,
      mime: file.mimetype,
      size: file.size,
      url,
    });
    // 广播附件变更
    const existing = await (await import('@/config/database')).prisma.note.findUnique({ where: { id }, select: { groupId: true }});
    const me = await prisma.user.findUnique({ where: { id: req.user!.id }, select: { partnerId: true } });
    const notify = [req.user!.id, ...(me?.partnerId ? [me.partnerId] : [])].map(uid => `user_${uid}`);
    SocketService.instance?.getIO().to(notify).emit('notes_updated', { scope: 'attachments', groupId: existing?.groupId, noteId: id });
    res.json({ success: true, data: att });
  }),
  listAttachments: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const { id } = req.params; // noteId
    const list = await NotesService.listAttachments(id);
    res.json({ success: true, data: list });
  }),
  deleteAttachment: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const { attachmentId } = req.params;
    await NotesService.removeAttachment(attachmentId);
    res.json({ success: true, message: '附件已删除' });
  }),
  // Share APIs
  shareGroup: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const { id } = req.params; // groupId
    const { userIds } = req.body as { userIds: string[] };
    const g = await NotesService.shareGroup(id, userIds || []);
    const notifyIds = await NotesService.getGroupSharedUserIds(id);
    SocketService.instance?.getIO().to(notifyIds.map(uid => `user_${uid}`)).emit('notes_updated', { scope: 'groups', groupId: id, shared: true });
    res.json({ success: true, data: g });
  }),
  unshareGroup: catchAsync(async (req: AuthenticatedRequest, res: Response) => {
    const { id, userId } = req.params; // groupId, userId
    const g = await NotesService.unshareGroup(id, userId);
    const notifyIds = await NotesService.getGroupSharedUserIds(id);
    SocketService.instance?.getIO().to(notifyIds.map(uid => `user_${uid}`)).emit('notes_updated', { scope: 'groups', groupId: id, shared: true });
    res.json({ success: true, data: g });
  }),
};